package com.javacoo.sftp.client.internal;

import java.util.Properties;

import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;

import com.javacoo.sftp.client.config.SftpClientConfig;
import com.javacoo.sftp.client.exception.SftpClientException;
import com.javacoo.sftp.client.template.SftpTemplate;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

import lombok.extern.slf4j.Slf4j;

/**
 * SftpTemplate工厂
 * <li></li>
 * @author duanyong@javacoo.com
 * @date 2020/5/14 11:33
 */
@Slf4j
public class SftpTemplateFactory extends BaseKeyedPooledObjectFactory<SftpClientConfig,SftpTemplate> {

    private static final String CHANNEL_TYPE = "sftp";
    private static Properties SHH_CONFIG = new Properties();
    static {
        SHH_CONFIG.put("StrictHostKeyChecking", "no");
    }

    /**
     * 创建一个SftpTemplate实例
     * 这个方法必须支持并发多线程调用
     * @author duanyong@javacoo.com
     * @date 2020/5/14 11:19
     * @param config:Sftp配置信息
     * @return: com.javacoo.sftp.client.template.SftpTemplate
     */
    @Override
    public SftpTemplate create(SftpClientConfig config) {
        try {
            JSch jsch = new JSch();
            Session sshSession = jsch.getSession(config.getUsername(), config.getHost(), config.getPort());
            sshSession.setPassword(config.getPassword());
            sshSession.setConfig(SHH_CONFIG);
            sshSession.setTimeout(config.getTimeout());
            sshSession.connect();
            ChannelSftp channel = (ChannelSftp) sshSession.openChannel(CHANNEL_TYPE);
            channel.connect();
            return new SftpTemplate(channel,config);
        } catch (Exception e) {
            log.error("客户端:{},连接sftp失败:{}",config, e.getMessage());
            throw new SftpClientException("客户端:{},连接sftp失败",e, config.toString());
        }
    }

    /**
     * 用PooledObject的实例包装对象
     * @author duanyong@javacoo.com
     * @date 2020/5/14 11:50
     * @param sftpTemplate 被包装的对象
     * @return: org.apache.commons.pool2.PooledObject<com.javacoo.sftp.client.template.SftpTemplate> 对象包装器
     */
    @Override
    public PooledObject<SftpTemplate> wrap(SftpTemplate sftpTemplate) {
        return new DefaultPooledObject<SftpTemplate>(sftpTemplate);
    }

    /**
     * 销毁对象
     * <li></li>
     * @author duanyong@javacoo.com
     * @date 2020/5/14 11:52
     * @param config:Sftp配置信息
     * @param p:包装对象
     * @return: void
     */
    @Override
    public void destroyObject(SftpClientConfig config,PooledObject<SftpTemplate> p) throws Exception{
        if (p!=null) {
            SftpTemplate sftpTemplate = p.getObject();
            if (sftpTemplate != null) {
                ChannelSftp channelSftp = sftpTemplate.getChannelSftp();
                if (channelSftp != null) {
                    channelSftp.disconnect();
                }
                sftpTemplate.setChannelSftp(null);
                sftpTemplate.setSftpClientConfig(null);
            }
        }
    }

    /**
     * 检查连接是否可用
     * <li></li>
     * @author duanyong@javacoo.com
     * @date 2020/5/14 11:54
     * @param config:Sftp配置信息
     * @param p:包装对象
     * @return: boolean
     */
    @Override
    public boolean validateObject(SftpClientConfig config,PooledObject<SftpTemplate> p){
        if (p != null) {
            SftpTemplate sftpTemplate = p.getObject();
            if (sftpTemplate != null) {
                try {
                    sftpTemplate.getChannelSftp().cd("./");
                    return true;
                } catch (SftpException e) {
                    return false;
                }
            }
        }
        return false;
    }
}
